/*
 * Wazuh Vulnerability Scanner - Unit Tests
 * Copyright (C) 2015, Wazuh Inc.
 * February 21, 2024.
 *
 * This program is free software; you can redistribute it
 * and/or modify it under the terms of the GNU General Public
 * License (version 2) as published by the FSF - Free Software
 * Foundation.
 */

#include "cleanAgentInventory_test.hpp"
#include "MockInventorySync.hpp"
#include "TrampolineOsDataCache.hpp"
#include "cleanAgentInventory.hpp"
#include "flatbuffers/include/syscollector_synchronization_schema.h"
#include "mocks/chainOfResponsabilityMock.h"

namespace NSCleanAgentInventoryTest
{

    const std::string SYNCHRONIZATION_INTEGRITY_CLEAR_PACKAGE_MSG =
        R"(
            {
                "agent_info": {
                    "agent_id": "001",
                    "agent_ip": "192.168.33.20",
                    "agent_name": "focal",
                    "node_name": "node01"
                },
                "data_type": "integrity_clear",
                "data": {
                    "id": 1700236640,
                    "attributes_type": "syscollector_packages"
                }
            }
        )";

    const std::string SYNCHRONIZATION_INTEGRITY_CLEAR_OS_MSG =
        R"(
            {
                "agent_info": {
                    "agent_id": "001",
                    "agent_ip": "192.168.33.20",
                    "agent_name": "focal",
                    "node_name": "node01"
                },
                "data_type": "integrity_clear",
                "data": {
                    "id": 1700236640,
                    "attributes_type": "syscollector_osinfo"
                }
            }
        )";

}; // namespace NSCleanAgentInventoryTest

using namespace NSCleanAgentInventoryTest;

void CleanAgentInventoryTest::SetUp()
{
    m_inventoryDatabase = std::make_unique<Utils::RocksDBWrapper>(INVENTORY_DB_PATH);
    for (const auto& element : AFFECTED_COMPONENT_COLUMNS)
    {
        if (!m_inventoryDatabase->columnExists(element.second))
        {
            m_inventoryDatabase->createColumn(element.second);
        }
    }

    if (!m_inventoryDatabase->columnExists(OS_INITIAL_SCAN))
    {
        m_inventoryDatabase->createColumn(OS_INITIAL_SCAN);
    }
    m_inventoryDatabase->put("node01_001_fdbd3c83c04c74d0cc7ad2f0e04ed88adfd74ad5",
                             "CVE-2021-33560,CVE-2019-13627,CVE-2021-40528");
    m_inventoryDatabase->put("node01_001_ec465b7eb5fa011a336e95614072e4c7f1a65a53", "CVE-2024-5678,CVE-2023-5362");
}

void CleanAgentInventoryTest::TearDown()
{
    spOsDataCacheMock.reset();
    m_inventoryDatabase->deleteAll();
    m_inventoryDatabase.reset();
    std::filesystem::remove_all(INVENTORY_DB_PATH);
}

TEST_F(CleanAgentInventoryTest, TestInstantiationOfTheeventInsertInventoryClass)
{
    // Instantiation of the eventInsertInventory class.
    EXPECT_NO_THROW(std::make_shared<TEventDeleteInventory<TScanContext<TrampolineOsDataCache>>>(*m_inventoryDatabase));
}

TEST_F(CleanAgentInventoryTest, CleanAgentDataSuccessfulPackage)
{
    // Created dummy data.
    m_inventoryDatabase->put(
        "node01_001_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "CVE-1234-2024,CVE-4321-2024", PACKAGE);
    m_inventoryDatabase->put("node01_001_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "CVE-1234-2024,CVE-4321-2024", OS);
    m_inventoryDatabase->put("node01_002_cccccccccccccccccccccccccccccccccccccccc", "CVE-1234-2024,CVE-4321-2024", OS);
    m_inventoryDatabase->put("001", "1", OS_INITIAL_SCAN);
    m_inventoryDatabase->put("002", "2", OS_INITIAL_SCAN);

    auto spSubOrchestration =
        std::make_shared<MockAbstractHandler<std::shared_ptr<TScanContext<TrampolineOsDataCache>>>>();
    EXPECT_CALL(*spSubOrchestration, handleRequest(testing::_)).Times(2);

    auto cleanAgentInventory = std::make_shared<
        TCleanAgentInventory<TScanContext<TrampolineOsDataCache>,
                             MockAbstractHandler<std::shared_ptr<TScanContext<TrampolineOsDataCache>>>>>(
        *m_inventoryDatabase, spSubOrchestration);

    nlohmann::json jsonData = nlohmann::json::parse(
        R"({"agent_info":  {"agent_id":"001",  "agent_version":"4.8.0",  "agent_name":"test_agent_name",
"agent_ip":"10.0.0.1",  "node_name":"node01"},  "action":"upgradeAgentDB"})");

    std::variant<const SyscollectorDeltas::Delta*, const SyscollectorSynchronization::SyncMsg*, const nlohmann::json*>
        data = &jsonData;
    auto context = std::make_shared<TScanContext<TrampolineOsDataCache>>(data);

    EXPECT_NO_THROW(cleanAgentInventory->handleRequest(context));

    // Check if the inventory was deleted.
    std::string value;
    EXPECT_FALSE(m_inventoryDatabase->get("node01_001_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", value, PACKAGE));
    EXPECT_FALSE(m_inventoryDatabase->get("node01_001_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", value, OS));
    EXPECT_TRUE(m_inventoryDatabase->get("node01_002_cccccccccccccccccccccccccccccccccccccccc", value, OS));
    EXPECT_FALSE(m_inventoryDatabase->get("001", value, OS_INITIAL_SCAN));
    EXPECT_TRUE(m_inventoryDatabase->get("002", value, OS_INITIAL_SCAN));
}

TEST_F(CleanAgentInventoryTest, CleanAgentDataIntegrityClear)
{
    // Created dummy data.
    m_inventoryDatabase->put(
        "node01_001_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "CVE-1234-2024,CVE-4321-2024", PACKAGE);
    m_inventoryDatabase->put("node01_001_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "CVE-1234-2024,CVE-4321-2024", OS);
    m_inventoryDatabase->put("node01_002_cccccccccccccccccccccccccccccccccccccccc", "CVE-1234-2024,CVE-4321-2024", OS);
    m_inventoryDatabase->put("001", "1", OS_INITIAL_SCAN);
    m_inventoryDatabase->put("002", "2", OS_INITIAL_SCAN);

    auto spSubOrchestration =
        std::make_shared<MockAbstractHandler<std::shared_ptr<TScanContext<TrampolineOsDataCache>>>>();
    EXPECT_CALL(*spSubOrchestration, handleRequest(testing::_)).Times(1);

    auto cleanAgentInventory = std::make_shared<
        TCleanAgentInventory<TScanContext<TrampolineOsDataCache>,
                             MockAbstractHandler<std::shared_ptr<TScanContext<TrampolineOsDataCache>>>>>(
        *m_inventoryDatabase, spSubOrchestration);

    flatbuffers::Parser parser;
    ASSERT_TRUE(parser.Parse(syscollector_synchronization_SCHEMA));
    ASSERT_TRUE(parser.Parse(SYNCHRONIZATION_INTEGRITY_CLEAR_PACKAGE_MSG.c_str()));
    uint8_t* buffer = parser.builder_.GetBufferPointer();
    std::variant<const SyscollectorDeltas::Delta*, const SyscollectorSynchronization::SyncMsg*, const nlohmann::json*>
        msg = SyscollectorSynchronization::GetSyncMsg(reinterpret_cast<const char*>(buffer));

    auto context = std::make_shared<TScanContext<TrampolineOsDataCache>>(msg);

    EXPECT_NO_THROW(cleanAgentInventory->handleRequest(context));

    // Check if the inventory was deleted.
    std::string value;
    EXPECT_FALSE(m_inventoryDatabase->get("node01_001_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", value, PACKAGE));
    EXPECT_TRUE(m_inventoryDatabase->get("node01_001_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", value, OS));
    EXPECT_TRUE(m_inventoryDatabase->get("node01_002_cccccccccccccccccccccccccccccccccccccccc", value, OS));
    EXPECT_TRUE(m_inventoryDatabase->get("001", value, OS_INITIAL_SCAN));
    EXPECT_TRUE(m_inventoryDatabase->get("002", value, OS_INITIAL_SCAN));
}

TEST_F(CleanAgentInventoryTest, CleanAgentDataIntegrityClearOs)
{
    // Created dummy data.
    m_inventoryDatabase->put(
        "node01_001_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "CVE-1234-2024,CVE-4321-2024", PACKAGE);
    m_inventoryDatabase->put("node01_001_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "CVE-1234-2024,CVE-4321-2024", OS);
    m_inventoryDatabase->put("node01_002_cccccccccccccccccccccccccccccccccccccccc", "CVE-1234-2024,CVE-4321-2024", OS);
    m_inventoryDatabase->put("001", "1", OS_INITIAL_SCAN);
    m_inventoryDatabase->put("002", "2", OS_INITIAL_SCAN);

    auto spSubOrchestration =
        std::make_shared<MockAbstractHandler<std::shared_ptr<TScanContext<TrampolineOsDataCache>>>>();
    EXPECT_CALL(*spSubOrchestration, handleRequest(testing::_)).Times(1);

    auto cleanAgentInventory = std::make_shared<
        TCleanAgentInventory<TScanContext<TrampolineOsDataCache>,
                             MockAbstractHandler<std::shared_ptr<TScanContext<TrampolineOsDataCache>>>>>(
        *m_inventoryDatabase, spSubOrchestration);

    flatbuffers::Parser parser;
    ASSERT_TRUE(parser.Parse(syscollector_synchronization_SCHEMA));
    ASSERT_TRUE(parser.Parse(SYNCHRONIZATION_INTEGRITY_CLEAR_OS_MSG.c_str()));
    uint8_t* buffer = parser.builder_.GetBufferPointer();
    std::variant<const SyscollectorDeltas::Delta*, const SyscollectorSynchronization::SyncMsg*, const nlohmann::json*>
        msg = SyscollectorSynchronization::GetSyncMsg(reinterpret_cast<const char*>(buffer));

    auto context = std::make_shared<TScanContext<TrampolineOsDataCache>>(msg);

    EXPECT_NO_THROW(cleanAgentInventory->handleRequest(context));

    // Check if the inventory was deleted.
    std::string value;
    EXPECT_TRUE(m_inventoryDatabase->get("node01_001_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", value, PACKAGE));
    EXPECT_FALSE(m_inventoryDatabase->get("node01_001_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", value, OS));
    EXPECT_TRUE(m_inventoryDatabase->get("node01_002_cccccccccccccccccccccccccccccccccccccccc", value, OS));
    EXPECT_FALSE(m_inventoryDatabase->get("001", value, OS_INITIAL_SCAN));
    EXPECT_TRUE(m_inventoryDatabase->get("002", value, OS_INITIAL_SCAN));
}
